/*
 * @Author: lixu lixu@puchigames.com
 * @Date: 2025-06-16 10:17:13
 * @LastEditors: lixu lixu@puchigames.com
 * @LastEditTime: 2025-06-16 10:17:20
 * @FilePath: /go-helper/utils/random.go
 * @Description: 随机数生成工具函数，包含随机整数、随机字符串、随机数组、随机UUID等功能
 */
package ixUtils

import (
	"crypto/rand"
	"fmt"
	"math/big"
	"time"
)

const (
	// 数字和字母
	letterBytes   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	letterIdxBits = 6                    // 6 bits to represent a letter index
	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits

	// 数字
	numberBytes = "0123456789"

	// 特殊字符
	specialBytes = "!@#$%^&*()_+-=[]{}|;:,.<>?"
)

// RandomInt 生成指定范围内的随机整数 [min, max)
func RandomInt(min, max int) int {
	if min >= max {
		return min
	}
	n, err := rand.Int(rand.Reader, big.NewInt(int64(max-min)))
	if err != nil {
		return min
	}
	return int(n.Int64()) + min
}

// RandomInt64 生成指定范围内的随机int64 [min, max)
func RandomInt64(min, max int64) int64 {
	if min >= max {
		return min
	}
	n, err := rand.Int(rand.Reader, big.NewInt(max-min))
	if err != nil {
		return min
	}
	return n.Int64() + min
}

// RandomFloat64 生成指定范围内的随机float64 [min, max)
func RandomFloat64(min, max float64) float64 {
	if min >= max {
		return min
	}
	n, err := rand.Int(rand.Reader, big.NewInt(1<<53))
	if err != nil {
		return min
	}
	return min + (max-min)*float64(n.Int64())/float64(1<<53)
}

// RandomString 生成指定长度的随机字符串
func RandomString(n int) string {
	if n <= 0 {
		return ""
	}
	b := make([]byte, n)
	for i := 0; i < n; {
		if idx := int(RandomInt64(0, int64(len(letterBytes)))); idx < len(letterBytes) {
			b[i] = letterBytes[idx]
			i++
		}
	}
	return string(b)
}

// RandomNumberString 生成指定长度的随机数字字符串
func RandomNumberString(n int) string {
	if n <= 0 {
		return ""
	}
	b := make([]byte, n)
	for i := 0; i < n; {
		if idx := int(RandomInt64(0, int64(len(numberBytes)))); idx < len(numberBytes) {
			b[i] = numberBytes[idx]
			i++
		}
	}
	return string(b)
}

// RandomSpecialString 生成指定长度的随机特殊字符字符串
func RandomSpecialString(n int) string {
	if n <= 0 {
		return ""
	}
	b := make([]byte, n)
	for i := 0; i < n; {
		if idx := int(RandomInt64(0, int64(len(specialBytes)))); idx < len(specialBytes) {
			b[i] = specialBytes[idx]
			i++
		}
	}
	return string(b)
}

// RandomBytes 生成指定长度的随机字节数组
func RandomBytes(n int) []byte {
	if n <= 0 {
		return nil
	}
	b := make([]byte, n)
	_, err := rand.Read(b)
	if err != nil {
		// 如果加密随机数生成失败，使用伪随机数
		for i := range b {
			b[i] = byte(RandomInt(0, 256))
		}
	}
	return b
}

// RandomElement 从切片中随机选择一个元素
func RandomElement[T any](slice []T) T {
	if len(slice) == 0 {
		var zero T
		return zero
	}
	return slice[RandomInt(0, len(slice))]
}

// RandomElements 从切片中随机选择n个元素
func RandomElements[T any](slice []T, n int) []T {
	if len(slice) == 0 || n <= 0 {
		return nil
	}
	if n > len(slice) {
		n = len(slice)
	}

	result := make([]T, n)
	indexes := make([]int, len(slice))
	for i := range indexes {
		indexes[i] = i
	}

	for i := 0; i < n; i++ {
		j := RandomInt(i, len(indexes))
		indexes[i], indexes[j] = indexes[j], indexes[i]
		result[i] = slice[indexes[i]]
	}

	return result
}

// Shuffle 随机打乱切片
func Shuffle[T any](slice []T) {
	if len(slice) <= 1 {
		return
	}
	for i := len(slice) - 1; i > 0; i-- {
		j := RandomInt(0, i+1)
		slice[i], slice[j] = slice[j], slice[i]
	}
}

// RandomBool 生成随机布尔值
func RandomBool() bool {
	return RandomInt(0, 2) == 1
}

// RandomTime 生成指定时间范围内的随机时间
func RandomTime(start, end time.Time) time.Time {
	if start.After(end) {
		start, end = end, start
	}
	delta := end.Sub(start)
	randomDuration := time.Duration(RandomInt64(0, int64(delta)))
	return start.Add(randomDuration)
}

// RandomWeight 根据权重随机选择
func RandomWeight(weights []float64) int {
	if len(weights) == 0 {
		return -1
	}

	var sum float64
	for _, w := range weights {
		if w < 0 {
			return -1
		}
		sum += w
	}

	if sum == 0 {
		return RandomInt(0, len(weights))
	}

	r := RandomFloat64(0, sum)
	var cumsum float64
	for i, w := range weights {
		cumsum += w
		if r < cumsum {
			return i
		}
	}

	return len(weights) - 1
}

// RandomUUID 生成随机UUID
func RandomUUID() string {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		// 如果加密随机数生成失败，使用伪随机数
		for i := range b {
			b[i] = byte(RandomInt(0, 256))
		}
	}
	b[6] = (b[6] & 0x0f) | 0x40
	b[8] = (b[8] & 0x3f) | 0x80
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}
